#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

uint16_t cmds1[] = {
	0x036, 0x100, 0x021, 0x03a, 0x105, 0x0b2, 0x10c, 0x10c,
	0x100, 0x133, 0x133, 0x0b7, 0x135, 0x0bb
};

uint16_t cmds2[] = {
	0x036, 0x100, 0x021, 0x03a, 0x105, 0x0b2, 0x10c, 0x10c,
	0x100, 0x133, 0x133, 0x0b7, 0x135, 0x0bb, 0x11f, 0x0c0,
	0x12c, 0x0c2, 0x101, 0x0c3, 0x11d, 0x0c4, 0x120, 0x0c6,
	0x10f, 0x0d0, 0x1a4, 0x1a1, 0x0E4, 0x127, 0x100, 0x110,
	0x0e0, 0x1d0, 0x100, 0x114, 0x115, 0x113, 0x12c, 0x142,
	0x143, 0x14e, 0x109, 0x116, 0x114, 0x118, 0x121, 0x0e1,
	0x1d0, 0x100, 0x114, 0x115, 0x113, 0x10b, 0x143, 0x155,
	0x153, 0x10c, 0x117, 0x114, 0x123, 0x120, 0x011, 0x011
};

uint16_t cmds3[] = {
	0x02a, 0x100, 0x100, 0x100, 0x100,
	0x02b, 0x100, 0x100, 0x100, 0x100,
	0x02c, 0x100, 0x100
};

uint8_t dats1[] = {
	0x36, 0x00, 0x21, 0x3a, 0x05, 0xb2, 0x0c, 0x0c,
	0x00, 0x33, 0x33, 0xb7, 0x35, 0xbb
};

uint8_t dats2[] = {
	0x36, 0x00, 0x21, 0x3a, 0x05, 0xb2, 0x0c, 0x0c,
	0x00, 0x33, 0x33, 0xb7, 0x35, 0xbb, 0x1f, 0xc0,
	0x2c, 0xc2, 0x01, 0xc3, 0x1d, 0xc4, 0x20, 0xc6,
	0x0f, 0xd0, 0xa4, 0xa1, 0xE4, 0x27, 0x00, 0x10,
	0xe0, 0xd0, 0x00, 0x14, 0x15, 0x13, 0x2c, 0x42,
	0x43, 0x4e, 0x09, 0x16, 0x14, 0x18, 0x21, 0xe1,
	0xd0, 0x00, 0x14, 0x15, 0x13, 0x0b, 0x43, 0x55,
	0x53, 0x0c, 0x17, 0x14, 0x23, 0x20, 0x11, 0x11
};

/**
 * @brief 将 16bit 中低 9bit 有效数据双字节流, 转化为 8bit 比特流, 其中每 9bit 为最小有效单元
 *
 * @param bytes
 * @param len
 */
void spi_9bit_write(uint16_t* bytes, uint32_t len)
{
	int i = 0;      // 循环变量
	int r = 0;      // 取余数
	int g = 0;      // 8个一组，表示第几组
	                // bit数据被拆分为两部分, 一部分在前一个8bit中, 另一部分在后一个8bit中
	int next = 0;   // next  表示多少 bit 在后 8bit 中
	int offset = 0; // offset 表示多少 bit 在前 8bit 中
	int ilen = 0;   // 输入数据长度, 数据格式为 uint16_t, 其中低 9bit 为有效数据
	int olen = 0;   // 输出数据长度, 数据格式为 uint8_t, 其中 9bit 数据依次拼接在一起
	int fill = 0;   // 由于要 9 字节对齐, 额外填充的字节个数
	uint8_t* buf = NULL;

	ilen = len;
	if (ilen % 8 == 0) {
		olen = ilen / 8 * 9;
		fill = 0;
	} else {
		olen = (ilen / 8 + 1) * 9;
		fill = 8 - ilen % 8;
	}

	printf("ilen = %d\n", ilen);
	printf("olen = %d\n", olen);
	printf("fill = %d\n", fill);

	/* input value binary dump */
	for (i = 0; i < ilen; i++) {
		printf("%d%d%d%d%d%d%d%d%d",
		    (bytes[i] & 0x100) >> 8,
		    (bytes[i] & 0x080) >> 7,
		    (bytes[i] & 0x040) >> 6,
		    (bytes[i] & 0x020) >> 5,
		    (bytes[i] & 0x010) >> 4,
		    (bytes[i] & 0x008) >> 3,
		    (bytes[i] & 0x004) >> 2,
		    (bytes[i] & 0x002) >> 1,
		    (bytes[i] & 0x001));
	}
	printf("\n");

	buf = malloc(olen);
	memset(buf, 0, olen);
	for (i = 0; i < ilen; i++) {
		r = i % 8;
		g = i / 8;
		next = r + 1;
		offset = 8 - next;

		buf[g + i] |= (bytes[i] >> next);
		buf[g + i + 1] |= (bytes[i] << offset);
	}

	/* output value binary dump */
	for (i = 0; i < olen; i++) {
		printf("%d%d%d%d%d%d%d%d",
		    (buf[i] & 0x80) >> 7,
		    (buf[i] & 0x40) >> 6,
		    (buf[i] & 0x20) >> 5,
		    (buf[i] & 0x10) >> 4,
		    (buf[i] & 0x08) >> 3,
		    (buf[i] & 0x04) >> 2,
		    (buf[i] & 0x02) >> 1,
		    (buf[i] & 0x01));
	}
	printf("\n");

	/* input hex dump */
	for (i = 0; i < ilen; i++) {
		printf("0x%03x, ", bytes[i]);
	}
	printf("\n");

	/* output hex dump */
	for (i = 0; i < olen; i++) {
		printf("0x%02x,  ", buf[i]);
	}
	printf("\n");

	free(buf);
}

/**
 * @brief 将 8bit 字节流, 添加数据1b前缀, 转化为新的 8bit 比特流, 其中每 9bit 为最小有效单元
 *
 * @param bytes
 * @param len
 */
void spi_8bit_write(uint8_t* bytes, uint32_t len)
{
	int i = 0;      // 循环变量
	int r = 0;      // 取余数
	int g = 0;      // 8个一组，表示第几组
	                // bit数据被拆分为两部分, 一部分在前一个8bit中, 另一部分在后一个8bit中
	int next = 0;   // next  表示多少 bit 在后 8bit 中
	int offset = 0; // offset 表示多少 bit 在前 8bit 中
	int ilen = 0;   // 输入数据长度, 数据格式为 uint16_t, 其中低 9bit 为有效数据
	int olen = 0;   // 输出数据长度, 数据格式为 uint8_t, 其中 9bit 数据依次拼接在一起
	int fill = 0;   // 由于要 9 字节对齐, 额外填充的字节个数
	uint8_t* buf = NULL;

	ilen = len;
	if (ilen % 8 == 0) {
		olen = ilen / 8 * 9;
		fill = 0;
	} else {
		olen = (ilen / 8 + 1) * 9;
		fill = 8 - ilen % 8;
	}

	printf("ilen = %d\n", ilen);
	printf("olen = %d\n", olen);
	printf("fill = %d\n", fill);

	/* input value binary dump */
	for (i = 0; i < ilen; i++) {
		printf(" %d%d%d%d%d%d%d%d",
		    (bytes[i] & 0x80) >> 7,
		    (bytes[i] & 0x40) >> 6,
		    (bytes[i] & 0x20) >> 5,
		    (bytes[i] & 0x10) >> 4,
		    (bytes[i] & 0x08) >> 3,
		    (bytes[i] & 0x04) >> 2,
		    (bytes[i] & 0x02) >> 1,
		    (bytes[i] & 0x01));
	}
	printf("\n");

	buf = malloc(olen);
	memset(buf, 0, olen);
	for (i = 0; i < ilen; i++) {
		r = i % 8;
		g = i / 8;
		next = r + 1;
		offset = 8 - next;

		buf[g + i] |= ((bytes[i] >> next) | (1 << offset));
		buf[g + i + 1] |= (bytes[i] << offset);
	}

	/* output value binary dump */
	for (i = 0; i < olen; i++) {
		printf("%d%d%d%d%d%d%d%d",
		    (buf[i] & 0x80) >> 7,
		    (buf[i] & 0x40) >> 6,
		    (buf[i] & 0x20) >> 5,
		    (buf[i] & 0x10) >> 4,
		    (buf[i] & 0x08) >> 3,
		    (buf[i] & 0x04) >> 2,
		    (buf[i] & 0x02) >> 1,
		    (buf[i] & 0x01));
	}
	printf("\n");

	/* input hex dump */
	for (i = 0; i < ilen; i++) {
		printf("0x%02x, ", bytes[i]);
	}
	printf("\n");

	/* output hex dump */
	for (i = 0; i < olen; i++) {
		printf("0x%02x, ", buf[i]);
	}
	printf("\n");

	free(buf);
}

/**
 * @brief 将 8bit 字节流, 添加数据1b前缀, 转化为新的 8bit 比特流, 其中每 9bit 为最小有效单元
 *
 * @param bytes
 * @param len
 */
void spi_8bit_write_optimized(uint8_t* bytes, uint32_t len)
{
	int i = 0;
	int ilen = 0;
	int olen = 0;
	int fill = 0;
	uint8_t* ibuf = NULL;
	uint8_t* obuf = NULL;

	ilen = len;
	olen = (ilen + 7) / 8 * 9;
	fill = 8 - ilen % 8;
	if (8 == fill)
		fill = 0;
	printf("ilen = %d\n", ilen);
	printf("olen = %d\n", olen);
	printf("fill = %d\n", fill);

	/* input hex dump */
	for (i = 0; i < ilen; i++) {
		printf("0x%02x, ", bytes[i]);
	}
	printf("\n");

	memset(bytes + ilen, 0, olen - ilen);

	/* input value binary dump */
	for (i = 0; i < ilen; i++) {
		printf(" %d%d%d%d%d%d%d%d",
		    (bytes[i] & 0x80) >> 7,
		    (bytes[i] & 0x40) >> 6,
		    (bytes[i] & 0x20) >> 5,
		    (bytes[i] & 0x10) >> 4,
		    (bytes[i] & 0x08) >> 3,
		    (bytes[i] & 0x04) >> 2,
		    (bytes[i] & 0x02) >> 1,
		    (bytes[i] & 0x01));
	}
	printf("\n");

	ibuf = bytes + (ilen + 7) / 8 * 8;
	obuf = bytes + olen;
	while (obuf > bytes && ibuf > bytes) {
		obuf -= 9;
		ibuf -= 8;
		obuf[8] = ibuf[7];
		obuf[7] = ibuf[6] << 1 | 1 << 0;
		obuf[6] = ibuf[5] << 2 | 1 << 1 | ibuf[6] >> 7;
		obuf[5] = ibuf[4] << 3 | 1 << 2 | ibuf[5] >> 6;
		obuf[4] = ibuf[3] << 4 | 1 << 3 | ibuf[4] >> 5;
		obuf[3] = ibuf[2] << 5 | 1 << 4 | ibuf[3] >> 4;
		obuf[2] = ibuf[1] << 6 | 1 << 5 | ibuf[2] >> 3;
		obuf[1] = ibuf[0] << 7 | 1 << 6 | ibuf[1] >> 2;
		obuf[0] = 1 << 7 | ibuf[0] >> 1;
	}

	obuf = bytes + olen - 9;
	for (i = 0; i < fill; i++) {
		obuf[7 - i] &= ~((i + 1) << 0);
	}

	/* output value binary dump */
	for (i = 0; i < olen; i++) {
		printf("%d%d%d%d%d%d%d%d",
		    (bytes[i] & 0x80) >> 7,
		    (bytes[i] & 0x40) >> 6,
		    (bytes[i] & 0x20) >> 5,
		    (bytes[i] & 0x10) >> 4,
		    (bytes[i] & 0x08) >> 3,
		    (bytes[i] & 0x04) >> 2,
		    (bytes[i] & 0x02) >> 1,
		    (bytes[i] & 0x01));
	}
	printf("\n");

	/* output hex dump */
	for (i = 0; i < olen; i++) {
		printf("0x%02x, ", bytes[i]);
	}
	printf("\n");
}

int main()
{

	// spi_9bit_write(cmds1, sizeof(cmds1) / 2);
	// spi_9bit_write(cmds3, sizeof(cmds3) / 2);

	// spi_9bit_write(cmds2, sizeof(cmds2) / 2);
	// spi_8bit_write(dats2, sizeof(dats2));
#if 0
	spi_8bit_write(dats1, sizeof(dats1));
#else
	int i = 0;
	uint8_t* buf = NULL;

	buf = malloc((sizeof(dats1) + 7) / 8 * 9);
	for (i = 0; i < sizeof(dats1); i++) {
		buf[i] = dats1[i];
	}

	spi_8bit_write_optimized(buf, sizeof(dats1));
#endif
	return 0;
}
